home *** CD-ROM | disk | FTP | other *** search
- /* ProjectAlias.c: ProjectorDB alias management routines for ProjectDrag
- *
- * A set of applets for drag and drop source control by Tim Maroney.
- * See develop, issue 23 for details.
- *
- * Built on DropShell by Leonard Rosenthol, Stephan Somogyi, and Marshall Clow,
- * and using the MoreFiles utilities by Jim Luther.
- *
- * This software is free, but don't modify and redistribute it without
- * changing the status window to indicate your name and your changes!
- */
-
- #include <Errors.h>
- #include <Finder.h>
- #include <Resources.h>
- #include <Script.h>
- #include <TextUtils.h>
- #include <LowMem.h>
- #include <StandardFile.h>
-
- #include "ProjectAlias.h"
- #include "SourceServer.h"
- #include "MoreFiles.h"
- #include "MoreFilesExtras.h"
-
-
- typedef struct NameMapping
- {
- struct NameMapping *fNext;
- StringPtr fProjectName;
- StringPtr fFolderName;
- } NameMapping;
-
-
- OSErr FindProjectAliasFromProjectName(StringPtr topProjectName, StringPtr realProjectName,
- AliasHandle *aliasOut, Boolean isFolderName);
-
-
- /* does the folder have a ProjectorDB? */
-
- Boolean IsProjectorFolder(short vRefNum, long folderID)
- {
- CInfoPBRec pb;
- OSErr err;
-
- pb.hFileInfo.ioNamePtr = "\pProjectorDB";
- pb.hFileInfo.ioVRefNum = vRefNum;
- pb.hFileInfo.ioDirID = folderID;
- pb.hFileInfo.ioFDirIndex = 0;
- err = PBGetCatInfoSync(&pb);
- if (err != noErr) return false;
- return pb.hFileInfo.ioFlFndrInfo.fdType == 'MPSP';
- }
-
-
- /* Make an alias for a projector database in the preferences folder
- * so ProjectDrag can deal with the project.
- */
-
- OSErr MakeProjectAlias(short vRefNum, long folderID, AliasHandle *aliasOut)
- {
- AliasHandle alias = NULL;
- OSErr err = noErr;
- FSSpec aliasFile;
- FSSpec projectFile;
- short resRefNum;
- long testFolderID;
- Boolean verified = false;
-
- if (aliasOut != NULL)
- *aliasOut = NULL;
-
- /* Since people are human, they sometimes drag in non-topmost projects.
- * That's OK. Iterate up to the top-level project. We assume that any
- * folder containg a ProjectorDB is part of a hierarchy, so if the parent
- * contains one, we loop upwards.
- */
- testFolderID = folderID;
- while (IsProjectorFolder(vRefNum, testFolderID))
- {
- CInfoPBRec pb;
-
- /* the previously checked folder was indeed a Projector folder */
- verified = true;
- folderID = testFolderID;
-
- /* get the parent folder for the next test */
- pb.hFileInfo.ioNamePtr = NULL;
- pb.hFileInfo.ioVRefNum = vRefNum;
- pb.hFileInfo.ioDirID = testFolderID;
- pb.hFileInfo.ioFDirIndex = -1;
- err = PBGetCatInfoSync(&pb);
- if (err != noErr) break;
- testFolderID = pb.dirInfo.ioDrParID;
- }
- if (!verified) return fnfErr;
-
- /* get the name of the projector folder */
- err = FindPreferencesFolder(&aliasFile.vRefNum, &aliasFile.parID);
- if (err != noErr) return err;
- err = GetDirName(vRefNum, folderID, aliasFile.name);
- if (err != noErr) return err;
-
- /* make the alias */
- projectFile.vRefNum = vRefNum;
- projectFile.parID = folderID;
- projectFile.name[0] = 0;
- err = NewAlias(NULL, &projectFile, &alias);
- if (err != noErr) return err;
-
- /* make the alias file
- *
- * note -- officially the format of alias files is private. You should only
- * create them by sending a Make Alias Apple Event to the Finder. Maybe in
- * ProjectDrag 1.1. Just don't wave this around and say Apple endorses this
- * practice. It doesn't!
- *
- */
- FSpCreateResFile(&aliasFile, kSourceServerCreator, kSourceServerType, smSystemScript);
- err = ResError();
- if (err == dupFNErr)
- {
- /* alias already exists -- delete it & create new one */
- FSpDelete(&aliasFile);
- FSpCreateResFile(&aliasFile, kSourceServerCreator, kSourceServerType, smSystemScript);
- err = ResError();
- }
- if (err != noErr)
- {
- DisposeHandle((Handle)alias);
- return err;
- }
-
- /* open the alias file */
- resRefNum = FSpOpenResFile(&aliasFile, fsRdWrPerm);
- if (resRefNum < 0)
- {
- err = ResError();
- DisposeHandle((Handle)alias);
- FSpDelete(&aliasFile);
- return err;
- }
-
- /* add the alias resource */
- AddResource((Handle)alias, 'alis', 0, "\p");
- err = ResError();
- if (err != noErr)
- {
- CloseResFile(resRefNum);
- DisposeHandle((Handle)alias);
- FSpDelete(&aliasFile);
- return err;
- }
- if (aliasOut != NULL)
- {
- *aliasOut = alias;
- err = HandToHand((Handle*)aliasOut);
- if (err != noErr)
- {
- CloseResFile(resRefNum);
- *aliasOut = NULL;
- return err;
- }
- }
- CloseResFile(resRefNum);
-
- /* turn it into an alias file, name locked, not yet inited */
- err = FSpChangeFDFlags(&aliasFile, true, kIsAlias | kNameLocked);
- if (err == noErr)
- err = FSpChangeFDFlags(&aliasFile, false, kHasBeenInited);
- if (err != noErr)
- {
- FSpDelete(&aliasFile);
- if (aliasOut != NULL)
- {
- DisposeHandle((Handle)*aliasOut);
- *aliasOut = NULL;
- }
- return err;
- }
- return noErr;
- }
-
-
- /* see note above -- officially, getting an alias from a file this way is naughty.
- * However, ResolveAliasFile doesn't give any control over the flags to MatchAlias,
- * or even give you the alias handle, on which we call GetAliasInfo. Sorry!
- */
-
- OSErr GetAliasFromFile(FSSpec *file, AliasHandle *aliasOut)
- {
- short resRefNum;
- AliasHandle alias;
- FSSpec aliasFile;
-
- aliasFile.vRefNum = file->vRefNum;
- aliasFile.parID = file->parID;
- BlockMove(file->name, aliasFile.name, file->name[0] + 1);
- resRefNum = FSpOpenResFile(&aliasFile, fsRdPerm);
- if (resRefNum < 0)
- return ResError();
- alias = (AliasHandle)Get1IndResource('alis', 1);
- if (alias == NULL)
- {
- CloseResFile(resRefNum);
- FSpDelete(&aliasFile); /* bad file -- kill it */
- return resNotFound;
- }
- DetachResource((Handle)alias);
- *aliasOut = alias;
- CloseResFile(resRefNum);
- return noErr;
- }
-
-
- /* Strip the name of the leading project from a full project name */
-
- void GetTopProjectName(StringPtr projectName, StringPtr topProjectName)
- {
- StringPtr src = projectName + 1;
- StringPtr dst = topProjectName + 1;
- short len = projectName[0];
- short i;
-
- topProjectName[0] = 0;
- for (i = 0; i < len; i++)
- {
- if (*src == kProjectorPathSeparator)
- break;
- *dst++ = *src++;
- topProjectName[0]++;
- }
- }
-
-
- /* get a project name from a CKID resource */
-
- OSErr FindProjectAliasFromCKID(CKIDHandle theCKID, AliasHandle *aliasOut, StringPtr projectName)
- {
- Str31 topProjectName;
- Str31 realProjectName;
-
- /* extract the project name from the CKID */
- BlockMove((*theCKID)->projectPath, projectName, (*theCKID)->projectPath[0] + 1);
-
- /* find the leading project name */
- GetTopProjectName(projectName, topProjectName);
-
- /* now search the preferences folder */
- return FindProjectAliasFromProjectName(topProjectName, realProjectName, aliasOut, false);
- }
-
-
- void DeleteMapping(NameMapping *theMapping)
- {
- while (theMapping != NULL)
- {
- NameMapping *aMapping = theMapping->fNext;
- if (theMapping->fProjectName != NULL)
- DisposePtr((Ptr)theMapping->fProjectName);
- if (theMapping->fFolderName != NULL)
- DisposePtr((Ptr)theMapping->fFolderName);
- theMapping = aMapping;
- DisposePtr((Ptr)theMapping);
- }
- }
-
-
- OSErr AddNameMapping(StringPtr folderName, StringPtr projectName)
- {
- OSErr err;
- FSSpec file;
- Handle fileData = NULL;
- short refNum = -1;
- char c;
-
- /* find the preferences folder */
- err = FindPreferencesFolder(&file.vRefNum, &file.parID);
- if (err != noErr) goto ErrorExit;
-
- /* get the Folder Names file data */
- GetIndString(file.name, kProjectDragStrings, kNameMappingFile);
- err = GetFileData(&file, &fileData, &refNum);
- if (err == fnfErr)
- {
- /* create and open the file */
- err = FSpCreate(&file, 'MPS ', 'TEXT', smSystemScript);
- if (err != noErr) goto ErrorExit;
- err = FSpOpenDF(&file, fsRdWrPerm, &refNum);
- if (err != noErr) goto ErrorExit;
- fileData = TempNewHandle(0, &err);
- }
- if (err != noErr) goto ErrorExit;
-
- /* add a line containing the new mapping -- XXX -- assumes EOL at EOF */
- err = PtrAndHand(projectName + 1, fileData, projectName[0]);
- if (err != noErr) goto ErrorExit;
- c = '=';
- err = PtrAndHand(&c, fileData, 1);
- if (err != noErr) goto ErrorExit;
- err = PtrAndHand(folderName + 1, fileData, folderName[0]);
- if (err != noErr) goto ErrorExit;
- c = '\n';
- err = PtrAndHand(&c, fileData, 1);
- if (err != noErr) goto ErrorExit;
- err = WriteFileWithHeader(refNum, fileData, 0, NULL);
- if (err != noErr) goto ErrorExit;
-
- /* clean up and go */
- DisposeHandle(fileData);
- FSClose(refNum);
- return noErr;
-
- ErrorExit:
- if (fileData != NULL)
- DisposeHandle(fileData);
- if (refNum != -1)
- FSClose(refNum);
- return err;
- }
-
- /* Some individuals have decided to name their checkout folder something different
- * from their project name. For this reason we keep a file called "Folder Names".
- * This is a text file with lines of the form (e.g.) "InfoAccessProj=InfoAccess",
- * where the project name is first and the folder name second.
- */
-
- NameMapping *GetNameMapping(void)
- {
- OSErr err;
- FSSpec file;
- Handle fileData;
- short refNum;
- StringPtr fileLine;
- long fileLength;
- long fileLineLength;
- NameMapping *theMapping = NULL;
-
- /* find the preferences folder */
- err = FindPreferencesFolder(&file.vRefNum, &file.parID);
- if (err != noErr) return NULL;
-
- /* get the Folder Names file data */
- GetIndString(file.name, kProjectDragStrings, kNameMappingFile);
- err = GetFileData(&file, &fileData, &refNum);
- if (err != noErr) return NULL;
- FSClose(refNum);
-
- /* parse the strings */
- HLock(fileData);
- fileLength = GetHandleSize(fileData);
- fileLine = *fileData;
- fileLineLength = LineSize(fileLine, fileLength);
- do
- {
- short equalSign;
- short partLength;
-
- /* find the equal sign */
- for (equalSign = 0;
- equalSign < fileLineLength && fileLine[equalSign] != '=';
- equalSign++)
- ;
- if (equalSign < fileLineLength)
- {
- /* allocate the mapping struct */
- NameMapping *aMapping = (NameMapping*)NewPtrClear(sizeof(NameMapping));
- if (aMapping == NULL)
- {
- DisposeHandle(fileData);
- DeleteMapping(theMapping);
- return NULL;
- }
-
- /* extract the line up to the equal sign */
- partLength = equalSign;
- aMapping->fProjectName = NewPtr(partLength + 1);
- if (aMapping->fProjectName == NULL)
- {
- DisposePtr((Ptr)aMapping);
- DisposeHandle(fileData);
- DeleteMapping(theMapping);
- return NULL;
- }
- BlockMoveData(fileLine, aMapping->fProjectName + 1, partLength);
- aMapping->fProjectName[0] = partLength;
-
- /* extract the line after the equal sign -- XXX -- assumes EOL at EOF.... */
- partLength = (fileLineLength - equalSign) - 2;
- aMapping->fFolderName = NewPtr(partLength);
- if (aMapping->fFolderName == NULL)
- {
- DisposePtr((Ptr)aMapping->fProjectName);
- DisposePtr((Ptr)aMapping);
- DisposeHandle(fileData);
- DeleteMapping(theMapping);
- return NULL;
- }
- BlockMoveData(fileLine + equalSign + 1, aMapping->fFolderName + 1, partLength);
- aMapping->fFolderName[0] = partLength;
-
- /* link this mapping into the list */
- aMapping->fNext = theMapping;
- theMapping = aMapping;
- }
-
- /* next line */
- fileLine += fileLineLength;
- fileLength -= fileLineLength;
- fileLineLength = LineSize(fileLine, fileLength);
- } while (fileLength > 0);
-
- DisposeHandle(fileData);
- return theMapping;
- }
-
-
- /* Find the alias to the ProjectorDB based on the name of the project. */
-
- OSErr FindProjectAliasFromProjectName(StringPtr topProjectName, StringPtr realProjectName,
- AliasHandle *aliasOut, Boolean isFolderName)
- {
- CInfoPBRec pb;
- OSErr err = noErr;
- short vRefNum;
- long folderID;
-
- /* default real name is the name passed in */
- BlockMoveData(topProjectName, realProjectName, topProjectName[0] + 1);
-
- /* check for folder name mapping */
- if (isFolderName)
- {
- NameMapping *theMapping = GetNameMapping();
- if (theMapping != NULL)
- {
- NameMapping *aMapping;
- for (aMapping = theMapping; aMapping != NULL; aMapping = aMapping->fNext)
- {
- if (EqualString(topProjectName, aMapping->fFolderName, false, false))
- {
- BlockMoveData(aMapping->fProjectName, realProjectName, aMapping->fProjectName[0] + 1);
- break;
- }
- }
- DeleteMapping(theMapping);
- }
- }
-
- /* find the preferences folder */
- err = FindPreferencesFolder(&vRefNum, &folderID);
- if (err != noErr) return err;
-
- /* loop over the aliases in the preferences folder */
- for (pb.hFileInfo.ioFDirIndex = 1, err = noErr; err == noErr; pb.hFileInfo.ioFDirIndex++)
- {
- Str31 fileName;
- fileName[0] = 0;
- pb.hFileInfo.ioNamePtr = fileName;
- pb.hFileInfo.ioVRefNum = vRefNum;
- pb.hFileInfo.ioDirID = folderID;
- err = PBGetCatInfoSync(&pb);
- if (err == noErr && (pb.hFileInfo.ioFlAttrib & 0x10) == 0 && (pb.hFileInfo.ioFlFndrInfo.fdFlags & kIsAlias))
- {
- /* does the alias file name match the project name? */
- if (EqualString(realProjectName, fileName, false, false))
- {
- /* found it! now extract the alias handle */
- FSSpec file;
- file.vRefNum = vRefNum;
- file.parID = folderID;
- BlockMove(fileName, file.name, fileName[0] + 1);
- err = GetAliasFromFile(&file, aliasOut);
- return err;
- }
- }
- }
-
- return fnfErr; /* file not found error */
- }
-
-
- /* find the alias to a ProjectorDB based on a checkout folder */
-
- OSErr FindProjectAliasFromFolder(short vRefNum, long folderID, AliasHandle *aliasOut, StringPtr projectName)
- {
- CInfoPBRec pb;
- Str31 fileName;
- Str31 realProjectName;
- OSErr err = noErr;
- unsigned char sep[2];
-
- if (folderID == fsRtDirID || folderID == fsRtParID)
- return fnfErr; /* end of recursion */
-
- /* look for projector files in this folder; use one of them... */
- for (pb.hFileInfo.ioFDirIndex = 1; err == noErr; pb.hFileInfo.ioFDirIndex++)
- {
- fileName[0] = 0;
- pb.hFileInfo.ioNamePtr = fileName;
- pb.hFileInfo.ioVRefNum = vRefNum;
- pb.hFileInfo.ioDirID = folderID;
- err = PBGetCatInfoSync(&pb);
- if (err == noErr && (pb.hFileInfo.ioFlAttrib & 0x10) == 0 && pb.hFileInfo.ioFlRLgLen > 0)
- {
- /* it's a file and it has a resource fork -- get the CKID */
- CKIDHandle theCKID;
- FSSpec file;
-
- file.vRefNum = vRefNum;
- file.parID = folderID;
- BlockMove(fileName, file.name, fileName[0] + 1);
- err = ExtractCKID(&file, &theCKID);
- if (err == noErr)
- {
- err = FindProjectAliasFromCKID(theCKID, aliasOut, projectName);
- DisposeHandle((Handle)theCKID);
- if (err == noErr)
- return noErr;
- }
- }
- }
-
- /* that didn't work -- now try walking up the folders */
-
- /* set up the initial project name */
- sep[0] = 1;
- sep[1] = kProjectorPathSeparator;
-
- /* find the name of the folder specified in the arguments */
- fileName[0] = 0;
- pb.hFileInfo.ioNamePtr = fileName;
- pb.hFileInfo.ioVRefNum = vRefNum;
- pb.hFileInfo.ioDirID = folderID;
- pb.hFileInfo.ioFDirIndex = -1;
- err = PBGetCatInfoSync(&pb);
- if (err != noErr)
- return err;
-
- /* see if the argument folder is the project */
- err = FindProjectAliasFromProjectName(fileName, realProjectName, aliasOut, true);
- if (err == noErr)
- {
- projectName[0] = 0;
- AppendString(projectName, realProjectName);
- AppendString(projectName, sep);
- return noErr;
- }
-
- /* recurse upwards looking for a project */
- if (pb.dirInfo.ioDrParID != fsRtDirID && pb.dirInfo.ioDrParID != fsRtParID)
- {
- err = FindProjectAliasFromFolder(vRefNum, pb.dirInfo.ioDrParID, aliasOut, projectName);
- if (err == noErr)
- {
- AppendString(projectName, fileName);
- AppendString(projectName, sep);
- return noErr;
- }
- }
-
- return fnfErr; /* file not found error */
- }
-
-
- /* Given an alias to a ProjectorDB, mount it. */
-
- OSErr MountProjectAlias(AliasHandle alias, CStringHandle *output, CStringHandle *diagnostic)
- {
- OSErr err;
- short aliasCount = 1;
- FSSpec projectFile;
- Boolean needsUpdate;
- AEDesc command;
-
- *output = *diagnostic = NULL;
-
- /* resolve the alias to auto-mount the server */
- err = MatchAlias (NULL, kARMSearch + kARMMountVol, alias, &aliasCount, &projectFile, &needsUpdate, NULL, NULL);
- if (err != noErr)
- return err;
-
- /* is this project already mounted?
- * ProjectInfo -only -project <projectName>
- */
- err = CreateCommand(&command, "ProjectInfo");
- if (err == noErr)
- {
- Boolean alreadyMounted = false;
- err = AddCStringArg(&command, "-only");
- if (err == noErr)
- {
- err = AddProjectArg(&command, projectFile.name);
- if (err == noErr)
- {
- err = SourceServerCommand(&command, output, diagnostic, ProjectDragIdleProc, NULL);
- alreadyMounted = (err == noErr);
- if (*output != NULL)
- DisposeHandle((Handle)*output);
- if (*diagnostic != NULL)
- DisposeHandle((Handle)*diagnostic);
- *output = *diagnostic = NULL;
- }
- }
- AEDisposeDesc(&command);
- if (alreadyMounted)
- return noErr;
- else if (err < noErr) /* not mounted returns a positive error status (2) */
- return err;
- }
-
- /* send the MountProject command */
- err = CreateCommand(&command, "MountProject");
- if (err == noErr)
- {
- err = AddFileNameArg(&command, &projectFile);
- if (err == noErr)
- err = SourceServerCommand(&command, output, diagnostic, ProjectDragIdleProc, NULL);
- AEDisposeDesc(&command);
- }
- return err;
- }
-
-
- Boolean SelectProjectorDB(FSSpec *file, short strListID, short strIndex,
- FileFilterYDProcPtr filter, void *dataPtr)
- {
- OSType theType = 'MPSP';
- StandardFileReply reply;
- Str255 prompt;
- Point where;
- short vRefNum;
- long folderID;
- OSErr err;
-
- err = FindPreferencesFolder(&vRefNum, &folderID);
- if (err == noErr)
- {
- LMSetSFSaveDisk(-vRefNum);
- LMSetCurDirStore(folderID);
- }
- SetPt(&where, -1, -1);
- GetIndString(prompt, strListID, strIndex);
- ParamText(prompt, NULL, NULL, NULL);
- CustomGetFile (filter, 1, &theType, &reply, kSelectWithPromptDialog, where,
- NULL, NULL, NULL, NULL, dataPtr);
- if (reply.sfGood)
- *file = reply.sfFile;
- return reply.sfGood;
- }
-